package main

import (
	"chapter-05-interceptor/service"
	"context"
	"encoding/json"
	"golang.org/x/net/trace"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/credentials"
	"google.golang.org/grpc/grpclog"
	"google.golang.org/grpc/metadata"
	"log"
	"net"
	"net/http"
	"os"
	"path"
)

// 1、声明一个server，里面是未实现的字段
type server struct {
	service.UnimplementedSayHelloServer
}

// SayHello
// 2、必须要实现在hello.proto里声明的远程调用接口，否则客户端会报：
// rpc error: code = Unimplemented desc = method SayHello not implement
func (*server) SayHello(ctx context.Context, req *service.HelloRequest) (*service.HelloResponse, error) {
	marshal, _ := json.Marshal(req)
	log.Println("收到Grpc请求,args", string(marshal))
	return &service.HelloResponse{
		Name: "yangchao",
		Age:  "18",
	}, nil
}

const (
	// Address gRPC服务地址
	Address = "127.0.0.1:50052"
)

func main() {
	//1、注册服务
	grpc.EnableTracing = true
	listener, err := net.Listen("tcp", Address)
	//获取当前目录
	dir, err := os.Getwd()
	if err != nil {
		grpclog.Fatalf("Failed to get current directory: %v", err)
	}
	//配置 TLS认证相关文件
	creds, err := credentials.NewServerTLSFromFile(path.Join(dir, "/key/server.pem"), path.Join(dir, "/key/server.key"))
	if err != nil {
		grpclog.Fatalf("Failed to generate credentials %v", err)
	}
	var opts []grpc.ServerOption
	opts = append(opts, grpc.Creds(creds))

	// 注册interceptor
	opts = append(opts, grpc.UnaryInterceptor(interceptor))

	// 实例化grpc Server
	ser := grpc.NewServer(opts...)

	//2、注册服务
	service.RegisterSayHelloServer(ser, &server{})

	//3、监听服务端口

	if err != nil {
		log.Fatal("服务监听端口失败", err)
	}

	// 开启trace
	go startTrace()
	log.Println("Listen on " + Address)
	//4、启动服务
	_ = ser.Serve(listener)
}

// auth 验证Token
func auth(ctx context.Context) error {
	md, ok := metadata.FromIncomingContext(ctx)
	if !ok {
		return grpc.Errorf(codes.Unauthenticated, "无Token认证信息")
	}

	var (
		appid  string
		appkey string
	)

	if val, ok := md["appid"]; ok {
		appid = val[0]
	}

	if val, ok := md["appkey"]; ok {
		appkey = val[0]
	}

	if appid != "101010" || appkey != "i am key" {
		return grpc.Errorf(codes.Unauthenticated, "Token认证信息无效: appid=%s, appkey=%s", appid, appkey)
	}

	return nil
}

// interceptor 拦截器
func interceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
	err := auth(ctx)
	if err != nil {
		return nil, err
	}
	// 继续处理请求
	return handler(ctx, req)
}

func startTrace() {
	trace.AuthRequest = func(req *http.Request) (any, sensitive bool) {
		return true, true
	}
	go func() {
		err := http.ListenAndServe(":50051", nil)
		if err != nil {
			panic(err)
		}
	}()
	log.Println("Trace listen on 50051")
}
